package com.inkegz.message.repo

import android.content.Context
import android.util.SparseArray
import androidx.lifecycle.LiveData
import androidx.lifecycle.map
import com.inkegz.message.BuildConfig.DEBUG
import com.inkegz.message.entity.ConversationEntity
import com.inkegz.message.entity.ConversationEntity_
import com.inkegz.message.entity.MessageEntity
import com.inkegz.message.entity.MyObjectBox
import com.inkegz.message.repo.action.AddConversationAction
import com.inkegz.message.repo.action.AddMessageAction
import com.inkegz.message.repo.action.RemoveConversationAction
import com.inkegz.message.repo.action.RemoveMessageAction
import com.inkegz.message.repo.base.ConversationRepo
import com.inkegz.message.repo.base.MessageRepo
import com.inkegz.message.repo.base.ObjectBoxReducer
import com.inkegz.message.utils.queryConversation
import io.objectbox.BoxStore
import io.objectbox.android.AndroidObjectBrowser
import io.objectbox.android.ObjectBoxLiveData
import io.objectbox.kotlin.boxFor

@Suppress("DeferredResultUnused")
class ImRepo(context: Context, uid: Int = 0) : ConversationRepo, MessageRepo {

    private val objectBox: BoxStore = MyObjectBox.builder().androidContext(context).name("Message_Repository_$uid").build()

    private val reducer = ObjectBoxReducer(objectBox)

    private val conversationQuery = objectBox.boxFor(ConversationEntity::class).query().build()

    private val conversationLiveData = ObjectBoxLiveData(conversationQuery)

    init {
        if (DEBUG)
            AndroidObjectBrowser(objectBox).start(context)
    }

    /**
     * 获取 会话
     */
    override fun conversations(): LiveData<List<ConversationEntity>> = conversationLiveData

    /**
     * 获取 指定会话
     * @param conversationKey
     */
    fun conversations(conversationKey: String): LiveData<List<ConversationEntity>> = ObjectBoxLiveData(
        objectBox.boxFor(ConversationEntity::class)
            .query()
            .equal(ConversationEntity_.conversationKey, conversationKey)
            .build()
    )

    /**
     * 获取消息列表
     * @param conversationKey
     */
    override fun messages(conversationKey: String): LiveData<List<MessageEntity>> =
        conversations(conversationKey)
            .map { conversations ->
                conversations.firstOrNull()?.messages?.toList() ?: emptyList()
            }

    /**
     * 获取 会话 versionId
     * @param
     */
    override fun getConversationVersionId(selector: (ConversationEntity) -> Long) =
        conversationQuery.find().maxBy(selector)?.versionId ?: 0L

    /**
     * 获取 消息 versionId
     * @param
     */
    override fun getMessageVersionId(conversationKey: String, isMax: Boolean, selector: (MessageEntity) -> Long) =
        if (isMax)
            objectBox.queryConversation(conversationKey)?.messages?.maxBy(selector)?.versionId ?: 0L
        else
            objectBox.queryConversation(conversationKey)?.messages?.minBy(selector)?.versionId ?: 0L

    /**
     * 更新/新增 会话
     */
    override fun putConversations(vararg conversationArray: ConversationEntity) {
        reducer.reduceAsync(AddConversationAction(conversationArray.toList()))
    }

    /**
     * 更新/新增 消息
     */
    override fun putMessages(conversationKey: String, vararg messageArray: MessageEntity) {
        reducer.reduceAsync(AddMessageAction(conversationKey, messageArray.toList()))
    }

    /**
     * 删除 会话
     */
    fun removeConversation(conversationKey: String) {
        reducer.reduceAsync(RemoveConversationAction(conversationKey))
    }

    /**
     * 删除 消息
     */
    fun removeMessage(messageId: Long) {
        reducer.reduceAsync(RemoveMessageAction(messageId))
    }

    companion object {
        private val repos: SparseArray<ImRepo> = SparseArray()

        fun getRepo(context: Context, versionId: Int): ImRepo {
            return repos[versionId] ?: ImRepo(context, versionId)
                .apply { repos.put(versionId, this) }
        }
    }
}